-module(geographic_grid).

-export([grid_coding/2, hashing/1, hashing_str/1]).

-type position() :: {float(), float()}.

-spec grid_coding(position(), integer()) -> string().
grid_coding({Longitude, Latitude} = _Pos, Level) ->
    integer_to_list(Level) ++
    ns_code(Latitude) ++ integer_to_list(trunc(Latitude * level_factor(Level))) ++
    ew_code(Longitude) ++ integer_to_list(trunc(Longitude * level_factor(Level))).

-spec hashing(string()) -> binary().
hashing(GridCode) ->
    erlang:md5(GridCode).

-spec hashing_str(string()) -> string().
hashing_str(GridCode) ->
    <<Code:128>> = hashing(GridCode),
    [R] = io_lib:format("~.16B", [Code]),
    R.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% internal function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ew_code(Longitude) when Longitude =< 180 andalso Longitude >= 0 ->
    "E";
ew_code(_Longitude) ->
    "W".

ns_code(Latitude) when Latitude >= 0 ->
    "N";
ns_code(_Latitude) ->
    "S".

level_factor(1) ->
    1/8;
level_factor(2) ->
    1/4;
level_factor(3) ->
    1/2;
level_factor(4) ->
    1;
level_factor(5) ->
    2;
level_factor(6) ->
    4;
level_factor(7) ->
    8;
level_factor(8) ->
    16;
level_factor(9) ->
    32;
level_factor(10) ->
    64.

